package tv.geir.slackspace.interceptor;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;

import tv.geir.slackspace.common.ObjectSerializer;
import tv.geir.slackspace.common.SlackSpaceException;

public class ArgumentsLoggerInterceptor implements MethodBeforeAdvice {

	//private static Logger log = Logger.getLogger( ArgumentsLoggerInterceptor.class );
	
	
	
	private HashMap<Class,Method> classes;
	
	private boolean calculateObjectSize = false;
	
	public boolean isCalculateObjectSize() {
		return calculateObjectSize;
	}

	public void setCalculateObjectSize(boolean calculateObjectSize) {
		this.calculateObjectSize = calculateObjectSize;
	}

	public void before(Method method, Object[] arg1, Object arg2)
			throws Throwable {
		Log log = LogFactory.getLog( arg2.getClass() );
		if( !log.isDebugEnabled() ) {
			return;
		}
		
		for (Object o : arg1) {
			Class objectClass = o.getClass();
			Method toStringMethod = null;
			for (Entry<Class, Method> e : classes.entrySet()) {
				if( objectClass.isAssignableFrom( e.getKey() ) ) {
					toStringMethod = e.getValue();
				}			
			}
			if( toStringMethod != null ) {
				String toString = toStringMethod.invoke( o , new Object[] {} ).toString();
				StringBuffer sb = new StringBuffer( method.getName() );
				sb.append( "( ")
				  .append( o.getClass().getName() )
				  .append( " ) ")
				  .append( toString );
				if( calculateObjectSize ) {
					int length = new ObjectSerializer().serialize(o).length;
					sb.append( " argumentSize=" )
						.append( length )
						.append( "bytes" );
				}			
				log.debug( sb.toString());
			}
			
		}		
	}


	
	public void setClassTypesAndMethod(HashMap<String, String> classNames) {
		classes = new HashMap<Class, Method>();
		for (Entry<String,String> e : classNames.entrySet()) {
			try {
				Class c = Class.forName(e.getKey());
				Method m = c.getMethod( e.getValue(), null);
				classes.put( c, m );
			} catch (ClassNotFoundException cnfe) {
				throw new SlackSpaceException( cnfe );
			} catch (SecurityException se) {
				throw new SlackSpaceException( se );
			} catch (NoSuchMethodException nsme) {
				throw new SlackSpaceException( nsme );
			}
			
		}
	}
	
	

}
